将类型名作为强制类型转换运算符的做法是C语言的老式做法，C++ 为保持兼容而予以保留。

C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换：static\_cast、reinterpret\_cast、const\_cast 和 dynamic\_cast。

强制类型转换是有一定风险的，有的转换并不一定安全，如把整型数值转换成指针，把基类指针转换成派生类指针，把一种函数指针转换成另一种函数指针，把常量指针转换成非常量指针等。C++ 引入新的强制类型转换机制，主要是为了克服C语言强制类型转换的以下三个缺点。
\begin{enumerate}
    \item 没有从形式上体现转换功能和风险的不同。例如，将 int 强制转换成 double 是没有风险的，而将常量指针转换成非常量指针，将基类指针转换成派生类指针都是高风险的，而且后两者带来的风险不同（即可能引发不同种类的错误），C语言的强制类型转换形式对这些不同并不加以区分。
    \item 将多态基类指针转换成派生类指针时不检查安全性，即无法判断转换后的指针是否确实指向一个派生类对象。
    \item 难以在程序中寻找到底什么地方进行了强制类型转换。
\end{enumerate}
强制类型转换是引发程序运行时错误的一个原因，因此在程序出错时，可能就会想到是不是有哪些强制类型转换出了问题。

如果采用C语言的老式做法，要在程序中找出所有进行了强制类型转换的地方，显然是很麻烦的，因为这些转换没有统一的格式。

而用 C++ 的方式，则只需要查找\_cast字符串就可以了。甚至可以根据错误的类型，有针对性地专门查找某一种强制类型转换。例如，怀疑一个错误可能是由于使用了 reinterpret\_cast 导致的，就可以只查找reinterpret\_cast字符串。

C++ 强制类型转换运算符的用法如下：
强制类型转换运算符 <要转换到的类型> (待转换的表达式)

例如：
\begin{cpp}
    double d = static_cast <double> (3*5);  //将 3*5 的值转换成实数
\end{cpp}
下面分别介绍四种强制类型转换运算符。
\begin{enumerate}
    \item static\_cast： 用于进行比较“自然”和低风险的转换，如整型和浮点型、字符型之间的互相转换。另外，如果对象所属的类重载了强制类型转换运算符 T（如 T 是 int、int* 或其他类型名），则 static\_cast 也能用来进行对象到 T 类型的转换。
    \item static\_cast： 不能用于在不同类型的指针之间互相转换，也不能用于整型和指针之间的互相转换，当然也不能用于不同类型的引用之间的转换。因为这些属于风险比较高的转换。

          static\_cast 用法示例如下：
          \begin{cpp}
              #include <iostream>
              using namespace std;
              class A
                  {
                      public:
                      operator int() { return 1; }
                      operator char*() { return NULL; }
                  };
              int main()
              {
                      A a;
                      int n;
                      char* p = "New Dragon Inn";
                      n = static_cast <int> (3.14);  // n 的值变为 3
                      n = static_cast <int> (a);  //调用 a.operator int，n 的值变为 1
                      p = static_cast <char*> (a);  //调用 a.operator char*，p 的值变为 NULL
                      n = static_cast <int> (p);  //编译错误，static_cast不能将指针转换成整型
                      p = static_cast <char*> (n);  //编译错误，static_cast 不能将整型转换成指针
                      return 0;
                  }
          \end{cpp}
    \item reinterpret\_cast： 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时，执行的是逐个比特复制的操作。

          这种转换提供了很强的灵活性，但转换的安全性只能由程序员的细心来保证了。例如，程序员执意要把一个 int* 指针、函数指针或其他类型的指针转换成 string* 类型的指针也是可以的，至于以后用转换后的指针调用 string 类的成员函数引发错误，程序员也只能自行承担查找错误的烦琐工作：（C++ 标准不允许将函数指针转换成对象指针，但有些编译器，如 Visual Studio 2010，则支持这种转换）。

          reinterpret\_cast 用法示例如下：
          \begin{cpp}
              #include <iostream>
              using namespace std;
              class A
                  {
                      public:
                      int i;
                      int j;
                      A(int n):i(n),j(n) { }
                  };
              int main()
              {
                      A a(100);
                      int &r = reinterpret_cast<int&>(a); //强行让 r 引用 a
                      r = 200;  //把 a.i 变成了 200
                      cout << a.i << "," << a.j << endl;  // 输出 200,100
                      int n = 300;
                      A *pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 n
                      pa->i = 400;  // n 变成 400
                      pa->j = 500;  //此条语句不安全，很可能导致程序崩溃
                      cout << n << endl;  // 输出 400
                      long long la = 0x12345678abcdLL;
                      pa = reinterpret_cast<A*>(la); //la太长，只取低32位0x5678abcd拷贝给pa
                      unsigned int u = reinterpret_cast<unsigned int>(pa);//pa逐个比特拷贝到u
                      cout << hex << u << endl;  //输出 5678abcd
                      typedef void (* PF1) (int);
                      typedef int (* PF2) (int,char *);
                      PF1 pf1;  PF2 pf2;
                      pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换
                  }
          \end{cpp}
          程序的输出结果是：
          \begin{bash}
              200, 100
              400
              5678abed
          \end{bash}
          第 19 行的代码不安全，因为在编译器看来，pa->j 的存放位置就是 n 后面的 4 个字节。 本条语句会向这 4 个字节中写入 500。但这 4 个字节不知道是用来存放什么的，贸然向其中写入可能会导致程序错误甚至崩溃。

          上面程序中的各种转换都没有实际意义，只是为了演示 reinteipret\_cast 的用法而已。在编写黑客程序、病毒或反病毒程序时，也许会用到这样怪异的转换。

    \item reinterpret\_cast体现了 C++ 语言的设计思想：用户可以做任何操作，但要为自己的行为负责。
    \item const\_cast：运算符仅用于进行去除 const 属性的转换，它也是四个强制类型转换运算符中唯一能够去除 const 属性的运算符。

          将 const 引用转换为同类型的非 const 引用，将 const 指针转换为同类型的非 const 指针时可以使用 const\_cast 运算符。例如：
          \begin{cpp}
              const string s = "Inception";
              string& p = const_cast <string&> (s);
              string* ps = const_cast <string*> (&s);  // &s 的类型是 const string*
          \end{cpp}
    \item dynamic\_cast：用 reinterpret\_cast 可以将多态基类（包含虚函数的基类）的指针强制转换为派生类的指针，但是这种转换不检查安全性，即不检查转换后的指针是否确实指向一个派生类对象。dynamic\_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用，而且能够检查转换的安全性。对于不安全的指针转换，转换结果返回 NULL 指针。
    \item dynamic\_cast 是通过“运行时类型检查”来保证安全性的。dynamic\_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性，只好用 reinterpret\_cast 来完成。

          dynamic\_cast 示例程序如下：
          \begin{cpp}
              #include <iostream>
              #include <string>
              using namespace std;
              class Base
                  {  //有虚函数，因此是多态基类
                      public:
                      virtual ~Base() {}
                  };
              class Derived : public Base { };
              int main()
              {
                      Base b;
                      Derived d;
                      Derived* pd;
                      pd = reinterpret_cast <Derived*> (&b);
                      if (pd == NULL)
                      //此处pd不会为 NULL。reinterpret_cast不检查安全性，总是进行转换
                      cout << "unsafe reinterpret_cast" << endl; //不会执行
                      pd = dynamic_cast <Derived*> (&b);
                      if (pd == NULL)  //结果会是NULL，因为 &b 不指向派生类对象，此转换不安全
                      cout << "unsafe dynamic_cast1" << endl;  //会执行
                      pd = dynamic_cast <Derived*> (&d);  //安全的转换
                      if (pd == NULL)  //此处 pd 不会为 NULL
                      cout << "unsafe dynamic_cast2" << endl;  //不会执行
                      return 0;
                  }
          \end{cpp}
          程序的输出结果是：
          \begin{bash}
              unsafe dynamic_cast1
          \end{bash}
          第 20 行，通过判断 pd 的值是否为 NULL，就能知道第 19 行进行的转换是否是安全的。第 23 行同理。

          如果上面的程序中出现了下面的语句：
          \cppinline{Derived & r = dynamic_cast <Derived &> (b);}
\end{enumerate}
那该如何判断该转换是否安全呢？不存在空引用，因此不能通过返回值来判断转换是否安全。C++ 的解决办法是：dynamic\_cast 在进行引用的强制转换时，如果发现转换不安全，就会拋出一个异常，通过处理异常，就能发现不安全的转换。
\subsection{智能指针}
要确保用 new 动态分配的内存空间在程序的各条执行路径都能被释放是一件麻烦的事情。C++ 11 模板库的 <memory> 头文件中定义的智能指针，即 shared \_ptr 模板，就是用来部分解决这个问题的。

只要将 new 运算符返回的指针 p 交给一个 shared\_ptr 对象“托管”，就不必担心在哪里写delete p语句——实际上根本不需要编写这条语句，托管 p 的 shared\_ptr 对象在消亡时会自动执行delete p。而且，该 shared\_ptr 对象能像指针 p —样使用，即假设托管 p 的 shared\_ptr 对象叫作 ptr，那么 *ptr 就是 p 指向的对象。

通过 shared\_ptr 的构造函数，可以让 shared\_ptr 对象托管一个 new 运算符返回的指针，写法如下：
\cppinline{shared_ptr<T> ptr(new T);  // T 可以是 int、char、类等各种类型}

此后，ptr 就可以像 T* 类型的指针一样使用，即 *ptr 就是用 new 动态分配的那个对象。

多个 shared\_ptr 对象可以共同托管一个指针 p，当所有曾经托管 p 的 shared\_ptr 对象都解除了对其的托管时，就会执行delete p。

例如下面的程序：
\begin{cpp}
    #include <iostream>
    #include <memory>
    using namespace std;
    class A
        {
            public:
            int i;
            A(int n):i(n) { };
            ~A() { cout << i << " " << "destructed" << endl; }
        };
    int main()
    {
            shared_ptr<A> sp1(new A(2)); //A(2)由sp1托管，
            shared_ptr<A> sp2(sp1);       //A(2)同时交由sp2托管
            shared_ptr<A> sp3;
            sp3 = sp2;   //A(2)同时交由sp3托管
            cout << sp1->i << "," << sp2->i <<"," << sp3->i << endl;
            A * p = sp3.get();      // get返回托管的指针，p 指向 A(2)
            cout << p->i << endl;  //输出 2
            sp1.reset(new A(3));    // reset导致托管新的指针, 此时sp1托管A(3)
            sp2.reset(new A(4));    // sp2托管A(4)
            cout << sp1->i << endl; //输出 3
            sp3.reset(new A(5));    // sp3托管A(5),A(2)无人托管，被delete
            cout << "end" << endl;
            return 0;
        }
\end{cpp}
程序的输出结果如下：
\begin{bash}
    2,2,2
    2
    3
    2 destructed
    end
    5 destructed
    4 destructed
    3 destructed
\end{bash}
可以用第 14 行及第 16 行的形式让多个 sharecLptr 对象托管同一个指针。这多个 shared\_ptr 对象会共享一个对共同托管的指针的“托管计数”。有 n 个 shared\_ptr 对象托管同一个指针 p，则 p 的托管计数就是 n。当一个指针的托管计数减为 0 时，该指针会被释放。shared\_ptr 对象消亡或托管了新的指针，都会导致其原托管指针的托管计数减 1。

第 20、21 行，shared\_ptr 的 reset 成员函数可以使得对象解除对原托管指针的托管（如果有的话），并托管新的指针。原指针的托管计数会减 1。

输出的第 4 行说明，用 new 创建的动态对象 A(2) 被释放了。程序中没有写 delete 语句，而 A(2) 被释放，是因为程序的第 23 行执行后，已经没有 shared\_ptr 对象托管 A(2)，于是 A(2) 的托管计数变为 0。最后一个解除对 A(2) 托管的 shared\_ptr 对象会释放 A(2)。

main 函数结束时，sp1、sp2、sp3 对象消亡，各自将其托管的指针的托管计数减为 0，并且释放其托管的指针，于是会有以下输出：
\begin{bash}
    5 destructed
    4 destructed
    3 destructed
\end{bash}
只有指向动态分配的对象的指针才能交给 shared\_ptr 对象托管。将指向普通局部变量、全局变量的指针交给 shared\_ptr 托管，编译时不会有问题，但程序运行时会出错，因为不能析构一个并没有指向动态分配的内存空间的指针。

注意，不能用下面的方式使得两个 shared\_ptr 对象托管同一个指针：
\begin{cpp}
    A* p = new A(10);
    shared_ptr <A> sp1(p), sp2(p);
\end{cpp}
sp1 和 sp2 并不会共享同一个对 p 的托管计数，而是各自将对 p 的托管计数都记为 1（sp2 无法知道 p 已经被 sp1 托管过）。这样，当 sp1 消亡时要析构 p，sp2 消亡时要再次析构 p，这会导致程序崩溃。
\subsection{Lambda表达式}
使用 STL 时，往往会大量用到函数对象，为此要编写很多函数对象类。有的函数对象类只用来定义了一个对象，而且这个对象也只使用了一次，编写这样的函数对象类就有点浪费。

而且，定义函数对象类的地方和使用函数对象的地方可能相隔较远，看到函数对象，想要查看其 operator() 成员函数到底是做什么的也会比较麻烦。

对于只使用一次的函数对象类，能否直接在使用它的地方定义呢？Lambda 表达式能够解决这个问题。使用 Lambda 表达式可以减少程序中函数对象类的数量，使得程序更加优雅。

Lambda 表达式的定义形式如下：
\begin{bash}
    [外部变量访问方式说明符] (参数表) -> 返回值类型
    {
    语句块
    }
\end{bash}

其中，“外部变量访问方式说明符”可以是=或\&，表示\{\}中用到的、定义在\{\}外面的变量在\{\}中是否允许被改变。=表示不允许，\&表示允许。当然，在\{\}中也可以不使用定义在外面的变量。“-> 返回值类型”可以省略。

下面是一个合法的Lambda表达式：
\begin{cpp}
    [=] (int x, int y) -> bool {return x%10 < y%10; }
\end{cpp}
Lambda 表达式实际上是一个函数，只是它没有名字。下面的程序段使用了上面的 Lambda 表达式：
\begin{cpp}
    int a[4] = {11, 2, 33, 4};
    sort(a, a+4, [=](int x, int y) -> bool { return x%10 < y%10; } );
    for_each(a, a+4, [=](int x) { cout << x << " ";} );
\end{cpp}
这段程的输出结果是：
\begin{bash}
    11 2 33 4
\end{bash}
程序第 2 行使得数组 a 按个位数从小到大排序。具体的原理是：sort 在执行过程中，需要判断两个元素 x、y 的大小时，会以 x、y 作为参数，调用 Lambda 表达式所代表的函数，并根据返回值来判断 x、y 的大小。这样，就不用专门编写一个函数对象类了。

第 3 行，for\_each 的第 3 个参数是一个 Lambda 表达式。for\_each 执行过程中会依次以每个元素作为参数调用它，因此每个元素都被输出。

下面是用到了外部变量的Lambda表达式的程序：
\begin{cpp}
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int main()
    {
            int a[4] = { 1, 2, 3, 4 };
            int total = 0;
            for_each(a, a + 4, [&](int & x) { total += x; x *= 2; });
            cout << total << endl;  //输出 10
            for_each(a, a + 4, [=](int x) { cout << x << " "; });
            return 0;
        }
\end{cpp}
程序的输出结果如下：
\begin{bash}
    10
    2 4 6 8
\end{bash}

第 8 行，[\&]表示该 Lambda 表达式中用到的外部变量 total 是传引用的，其值可以在表达式执行过程中被改变（如果使用[=]，编译无法通过）。该 Lambda 表达式每次被 for\_each 执行时，都将 a 中的一个元素累加到 total 上，然后将该元素加倍。

实际上，“外部变量访问方式说明符”还可以有更加复杂和灵活的用法。例如：
[=, \&x, \&y]表示外部变量 x、y 的值可以被修改，其余外部变量不能被修改；
[\&, x, y]表示除 x、y 以外的外部变量，值都可以被修改。

例如下面的程序：
\begin{cpp}
    #include <iostream>
    using namespace std;
    int main()
    {
    int x = 100,y=200,z=300;
    auto ff  = [=,&y,&z](int n) {
            cout <<x << endl;
            y++; z++;
            return n*n;
        };
    cout << ff(15) << endl;
    cout << y << "," << z << endl;
    }
\end{cpp}
程序的输出结果如下：
\begin{bash}
    100
    225
    201, 301
\end{bash}
第 6 行定义了一个变量 ff，ff 的类型是 auto，表示由编译器自动判断其类型（这也是 C++11 的新特性）。本行将一个 Lambda 表达式赋值给 ff，以后就可以通过 ff 来调用该 Lambda 表达式了。

第 11 行通过 ff，以 15 作为参数 n 调用上面的 Lambda 表达式。该 Lambda 表达式指明，对于外部变量 y、z，可以修改其值；对于其他外部变量，例如 x，不能修改其值。因此在该表达式执行时，可以修改外部变量 y、z 的值，但如果出现试图修改 x 值的语句，就会编译出错。

可以用 auto 关键字定义变量，编译器会自动判断变量的类型。例如：
\begin{cpp}
    auto i =100;  // i 是 int
    auto p = new A();  // p 是 A*
    auto k = 34343LL;  // k 是 long long
\end{cpp}
有时，变量的类型名特别长，使用 auto 就会很方便。例如：
\begin{cpp}
    map <string, int, greater <string> >mp;
    for( auto i = mp.begin(); i != mp.end(); ++i)
    cout << i -> first << ", " << i -> second;
\end{cpp}
编译器会自动判断出 i 的类型是 map<string, int, greater<string> >::iterator。

decltype 关键字可以用于求表达式的类型。例如：
\begin{cpp}
    int i;
    double t;
    struct A { double x; };
    const A* a = new A();
    decltype(a) x1;  //x1 是 A*
    decltype(i) x2;  //x2 是 int
    decltype(a -> x) x3;  // x3 是 double
\end{cpp}
在上面的例子中，编译器自动将 decltype (a) 等价为A*，因为编译器知道 a 的类型是A*。

auto 和 decltype 可以一起使用。例如：
\begin{cpp}
    #include <iostream>
    using namespace std;
    struct A {
            int i;
            A(int ii) : i(ii) {}
        };
    A operator + (int n, const A & a)
    {
            return A(a.i + n);
        }
    template <class T1, class T2>
    auto add(T1 x, T2 y) -> decltype(x + y) {
            return x + y;
        }
    int main() {
            auto d = add(100, 1.5);  // d 是 double 类型，d = 101.5
            auto k = add(100, A(1));  // k 是 A 类型，因为表达式“100+A(1)”是A类型的
            cout << d << endl;
            cout << k.i << endl;
            return 0;
        }
\end{cpp}
程序的输出结果如下：
\begin{bash}
    101.5
    101
\end{bash}
第 12 行告诉编译器，add 的返回值类型是decltype(x+y)，即返回值的类型和x+y这个表达式的类型一致。编译器将 add 实例化时，会自动推断出x+y的类型。

在 C++11 中，函数返回值若为 auto，则需要和 decltype 配合使用。在 C++14 中，则可以不用 decltype，例如下面的程序没有问题：
\begin{cpp}
    auto add (int a, int b)
    {
            int i = a + b;
            return i;
        }
\end{cpp}
\subsection{右值引用}
能出现在赋值号左边的表达式称为“左值”，不能出现在赋值号左边的表达式称为“右值”。一般来说，左值是可以取地址的，右值则不可以。

非 const 的变量都是左值。函数调用的返回值若不是引用，则该函数调用就是右值。前面所学的“引用”都是引用变量的，而变量是左值，因此它们都是“左值引用”。

C++11 新增了一种引用，可以引用右值，因而称为“右值引用”。无名的临时变量不能出现在赋值号左边，因而是右值。右值引用就可以引用无名的临时变量。定义右值引用的格式如下：
类型 \&\& 引用名 = 右值表达式;

例如：
\begin{cpp}
    class A{};
    A & rl = A();  //错误，无名临时变量 A() 是右值，因此不能初始化左值引用 r1
    A && r2 = A();  //正确，因 r2 是右值引用
\end{cpp}
引入右值引用的主要目的是提高程序运行的效率。有些对象在复制时需要进行深复制，深复制往往非常耗时。合理使用右值引用可以避免没有必要的深复制操作。例如下面的程序：
\begin{cpp}
    #include <iostream>
    #include <string>
    #include <cstring>
    using namespace std;
    class String
        {
            public:
            char* str;
            String() : str(new char[1]) { str[0] = 0; }
            String(const char* s) {
                    str = new char[strlen(s) + 1];
                    strcpy(str, s);
                }
            String(const String & s) {//复制构造函数
                    cout << "copy constructor called" << endl;
                    str = new char[strlen(s.str) + 1];
                    strcpy(str, s.str);
                }
            String & operator = (const String & s) {//复制赋值号
                    cout << "copy operator = called" << endl;
                    if (str != s.str) {
                            delete[] str;
                            str = new char[strlen(s.str) + 1];
                            strcpy(str, s.str);
                        }
                    return *this;
                }
            String(String && s) : str(s.str) { //移动构造函数
                    cout << "move constructor called" << endl;
                    s.str = new char[1];
                    s.str[0] = 0;
                }
            String & operator = (String && s) { //移动赋值号
                    cout << "move operator = called" << endl;
                    if (str != s.str) {
                            str = s.str;
                            s.str = new char[1];
                            s.str[0] = 0;
                        }
                    return *this;
                }
            ~String() { delete[] str; }
        };
    template <class T>
    void MoveSwap(T & a, T & b) {
            T tmp(move(a));  //std::move(a) 为右值，这里会调用移动构造函数
            a = move(b);  //move(b) 为右值，因此这里会调用移动赋值号
            b = move(tmp);  //move(tmp) 为右值，因此这里会调用移动赋值号
        }
    int main()
    {
            String s;
            s = String("this");  //调用移动赋值号
            cout << "* * * *" << endl;
            cout << s.str << endl;
            String s1 = "hello", s2 = "world";
            MoveSwap(s1, s2);  //调用一次移动构造函数和两次移动赋值号
            cout << s2.str << endl;
            return 0;
        }
\end{cpp}
程序的输出结果如下：
\begin{bash}
    move operator = called
    ****
    this
    move constructor called
    move operator = called
    move operator = called
    hello
\end{bash}
第 33 行重载了一个移动赋值号。它和第 19 行的复制赋值号的区别在于，其参数是右值引用。在移动赋值号函数中没有执行深复制操作，而是直接将对象的 str 指向了参数 s 的成员变量 str 指向的地方，然后修改 s.str 让它指向别处，以免 s.str 原来指向的空间被释放两次。

该移动赋值号函数修改了参数，这会不会带来麻烦呢？答案是不会。因为移动赋值号函数的形参是一个右值引用，则调用该函数时，实参一定是右值。右值一般是无名临时变量，而无名临时变量在使用它的语句结束后就不再有用，因此其值即使被修改也没有关系。

第 53 行，如果没有定义移动赋值号，则会导致复制赋值号被调用，引发深复制操作。临时无名变量String("this")是右值，因此在定义了移动赋值号的情况下，会导致移动赋值号被调用。移动赋值号使得 s 的内容和 String("this") 一致，然而却不用执行深复制操作，因而效率比复制赋值号高。

虽然移动赋值号修改了临时变量 String("this")，但该变量在后面已无用处，因此这样的修改不会导致错误。

第 46 行使用了 C++ 11 中的标准模板 move。move 能接受一个左值作为参数，返回该左值的右值引用。因此本行会用定义于第 28 行、以右值引用作为参数的移动构造函数来初始化 tmp。该移动构造函数没有执行深复制，将 tmp 的内容变成和 a 相同，然后修改 a。由于调用 MoveSwap 本来就会修改 a，所以 a 的值在此处被修改不会产生问题。

第 47 行和第 48 行调用了移动赋值号，在没有进行深复制的情况下完成了 a 和 b 内容的互换。对比 Swap 函数的以下写法：
\begin{cpp}
    template <class T>
    void Swap(T & a, T & b) {
            T tmp(a);  //调用复制构造函数
            a=b;  //调用复制赋值号
            b=tmp;  //调用复制赋值号
        }
\end{cpp}
Swap 函数执行期间会调用一次复制构造函数，两次复制赋值号，即一共会进行三次深复制操作。而利用右值引用，使用 MoveSwap，则可以在无须进行深复制的情况下达到相同的目的，从而提高了程序的运行效率。

\section{Regex库}
\subsection{std::basic\_regex}

